using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

namespace AloneLibrary.Services.Input
{

	/// <summary>
	/// Struct for passing key actions
	/// </summary>
	public struct ActionButtonStatus
	{
		public bool Status;
		public bool Updated;
	}

	/// <summary>
	/// This is a game component that implements IUpdateable.
	/// </summary>
	public class KeyboardInputHandler : Microsoft.Xna.Framework.GameComponent, IInputHandler
	{
		#region IInputHandler

		// IInputHandler
		private ActionButtonStatus start, back, fire, jump, boost, reload, aim;

		public ActionButtonStatus Start { get { return start; } }
		public ActionButtonStatus Back { get { return back; } }
		public ActionButtonStatus Fire { get { return fire; } }
		public ActionButtonStatus Jump { get { return jump; } }
		public ActionButtonStatus Boost { get { return boost; } }
		public ActionButtonStatus Reload { get { return reload; } }
		public ActionButtonStatus Aim { get { return aim; } }

		private Vector2 movement = Vector2.Zero;
		private Vector2 rotation = Vector2.Zero;
		public Vector2 Movement
		{
			get { return movement; }
		}
		public Vector2 Rotation
		{
			get { return rotation; }
		}

		private float zoom = 0f;
		public float Zoom
		{
			get { return zoom; }
		}
		#endregion

		private MouseState mouseState, prevMouseState;
		private KeyboardState keyboardState, prevKeyboardState;
		private GamePadState gamePadState, prevGamePadState;
		private ButtonState prevLeftMouse, prevRightMouse;
		private float mouseSensitivity = 0.2f;
		public float MouseSensitivity
		{
			get { return mouseSensitivity; }
			set { mouseSensitivity = value; }
		}

		private Point centerScreen;

		/// <summary>
		/// Initializes a new instance of the <see cref="KeyboardInputHandler"/> class.
		/// </summary>
		/// <param name="game">Game that the game component should be attached to.</param>
		public KeyboardInputHandler(Game game)
			: base(game)
		{
			game.Services.AddService(typeof(IInputHandler), this);
		}

		/// <summary>
		/// Allows the game component to perform any initialization it needs to before starting
		/// to run.  This is where it can query for any required services and load content.
		/// </summary>
		public override void Initialize()
		{
			centerScreen = new Point(Game.GraphicsDevice.Viewport.X / 2, Game.GraphicsDevice.Viewport.Y / 2);

			Game.IsMouseVisible = false;

			Mouse.SetPosition(centerScreen.X, centerScreen.Y);
			prevMouseState = Mouse.GetState();

			base.Initialize();
		}

		/// <summary>
		/// Allows the game component to update itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		public override void Update(GameTime gameTime)
		{
			keyboardState = Keyboard.GetState();
			mouseState = Mouse.GetState();
			gamePadState = GamePad.GetState(PlayerIndex.One);

			if (gamePadState.ThumbSticks.Right != Vector2.Zero)
			{
				movement.X = gamePadState.ThumbSticks.Right.X;
				movement.Y = gamePadState.ThumbSticks.Right.Y;
			}
			else
			{
				movement.X = (keyboardState.IsKeyDown(Keys.A) ? -1 : (keyboardState.IsKeyDown(Keys.D) ? 1 : 0));
				movement.Y = (keyboardState.IsKeyDown(Keys.S) ? -1 : (keyboardState.IsKeyDown(Keys.W) ? 1 : 0));
			}

			if (gamePadState.ThumbSticks.Left != Vector2.Zero)
			{
				rotation.X = gamePadState.ThumbSticks.Left.Y;
				rotation.Y = gamePadState.ThumbSticks.Left.X;
			}
			else
			{
				float amount = ((float)gameTime.ElapsedGameTime.Milliseconds / 1000f) * mouseSensitivity;
				rotation.X = (mouseState.Y - prevMouseState.Y) * amount;
				rotation.Y = (mouseState.X - prevMouseState.X) * amount;
			}

			start.Status = keyboardState.IsKeyDown(Keys.Enter) || gamePadState.IsButtonDown(Buttons.Start);
			start.Updated = start.Status && (prevKeyboardState.IsKeyUp(Keys.Enter) || prevGamePadState.IsButtonUp(Buttons.Start));

			back.Status = keyboardState.IsKeyDown(Keys.Escape) || gamePadState.IsButtonDown(Buttons.Back);
			back.Updated = back.Status && (prevKeyboardState.IsKeyUp(Keys.Escape) || prevGamePadState.IsButtonUp(Buttons.Back));

			jump.Status = keyboardState.IsKeyDown(Keys.Space) || gamePadState.IsButtonDown(Buttons.A);
			jump.Updated = jump.Status && (prevKeyboardState.IsKeyUp(Keys.Space) || prevGamePadState.IsButtonUp(Buttons.A));

			boost.Status = keyboardState.IsKeyDown(Keys.Q) || gamePadState.IsButtonDown(Buttons.X);
			boost.Updated = boost.Status && (prevKeyboardState.IsKeyUp(Keys.Q) || prevGamePadState.IsButtonUp(Buttons.X));

			reload.Status = keyboardState.IsKeyDown(Keys.R) || gamePadState.IsButtonDown(Buttons.Back);
			reload.Updated = reload.Status && (prevKeyboardState.IsKeyUp(Keys.R) || prevGamePadState.IsButtonUp(Buttons.B));

			fire.Status = mouseState.LeftButton == ButtonState.Pressed || gamePadState.IsButtonDown(Buttons.RightTrigger);
			fire.Updated = fire.Status && (prevLeftMouse == ButtonState.Released || prevGamePadState.IsButtonUp(Buttons.RightTrigger));

			aim.Status = mouseState.RightButton == ButtonState.Pressed || gamePadState.IsButtonDown(Buttons.LeftTrigger);
			aim.Updated = aim.Status && (prevRightMouse == ButtonState.Released || prevGamePadState.IsButtonUp(Buttons.LeftTrigger));
			
			prevGamePadState = gamePadState;
			prevKeyboardState = keyboardState;

			prevLeftMouse = mouseState.LeftButton;
			prevRightMouse = mouseState.RightButton;
			
			Mouse.SetPosition(centerScreen.X, centerScreen.Y);
			//prevMouseState = mouseState;

			base.Update(gameTime);
		}
	}
}